package com.sbtr.controller.classify;

import cn.hutool.json.JSONUtil;
import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sbtr.business.classify.dto.AlgoTemplateFileDto;
import com.sbtr.business.classify.entity.AlgoTemplateFile;
import com.sbtr.business.classify.service.AlgoTemplateFileService;
import com.sbtr.business.feature.dto.FeDatafileUploadDto;
import com.sbtr.business.trainingserver.balancer.ITraningServerBalancer;
import com.sbtr.business.trainingserver.service.impl.TrainingServerServiceImpl;
import com.sbtr.common.LoginConstants;
import com.sbtr.common.PageDto;
import com.sbtr.common.PageParams;
import com.sbtr.common.Response;
import com.sbtr.common.calculate.CalculateAnalysisReflectUtil;
import com.sbtr.common.calculate.DataAnalysisUtil;
import com.sbtr.common.enums.DataTypeEnum;
import com.sbtr.common.file.CommonAnalyzeService;
import com.sbtr.common.file.FileService;
import com.sbtr.common.file.dto.FileContentDto;
import com.sbtr.common.file.dto.FileDto;
import com.sbtr.common.file.utils.AbstractNoModelDataListener;
import com.sbtr.common.interfaces.CalculateAnalysis;
import com.sbtr.common.util.DataObjectConvertUtil;
import com.sbtr.controller.common.CommonController;
import com.sbtr.exception.BDException;
import com.sbtr.open.trainingserver.dto.TrainingServerDto;
import com.sbtr.util.BeanCopyUtils;
import com.sbtr.util.PageDtoUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.util.*;

/**
 * 轻量化算法模板字段列表 前端控制器a
 *
 * @author dgl
 * @since 2023-06-13
 */
@RestController
@RequestMapping("/algoTemplateFile")
@Api(tags = "轻量化算法模板字段列表")
public class AlgoTemplateFileController extends CommonController<AlgoTemplateFile, AlgoTemplateFileService> {

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private CommonAnalyzeService commonAnalyzeService;
    @Autowired
    private FileService fileService;
    @Autowired
    private ITraningServerBalancer serverBalancer;

    @GetMapping("/pageList")
    @ApiOperation(httpMethod = "GET", value = "分页列表")
    public Response<PageDto<AlgoTemplateFile>> pageList(AlgoTemplateFileDto algoTemplateFileDto) {
        return Response.success(u.pageList(algoTemplateFileDto));
    }

    @PostMapping("/save")
    @ApiOperation(httpMethod = "POST", value = "保存")
    public Response<AlgoTemplateFile> save(AlgoTemplateFile algoTemplateFile, @RequestParam(value = "file", required = false) MultipartFile file) {
        algoTemplateFile.setId(null);
        algoTemplateFile.setCreateTime(new Date());
        if (file != null) {
            FileDto fileDto = fileService.uploadFile(file, new FileDto("testAlgo"));

            AbstractNoModelDataListener abstractNoModelDataListener = new AbstractNoModelDataListener(commonAnalyzeService, new HashMap<>());
            EasyExcel.read(fileDto.getPath(), abstractNoModelDataListener).sheet().doRead();

            FileContentDto fileContentDto = new FileContentDto();
            fileContentDto.setContent(abstractNoModelDataListener.resultDataList);
            fileContentDto.setTitle(abstractNoModelDataListener.titleList);

            List<List<String>> linkedHashMaps = fileContentDto.getListList();
            if (CollectionUtils.isEmpty(linkedHashMaps)) {
                throw new BDException("缺少内容");
            }

            if (algoTemplateFile.getModelCode().equals("1")) {
                AbstractNoModelDataListener abstractNoModelDataListener2 = new AbstractNoModelDataListener(commonAnalyzeService, new HashMap<>());
                EasyExcel.read(fileDto.getPath(), abstractNoModelDataListener2).sheet(1).doRead();

                FileContentDto fileContentDto2 = new FileContentDto();
                fileContentDto2.setContent(abstractNoModelDataListener2.resultDataList);
                fileContentDto2.setTitle(abstractNoModelDataListener2.titleList);

                List<List<String>> linkedHashMaps2 = fileContentDto2.getListList();
                if (CollectionUtils.isEmpty(linkedHashMaps2) || CollectionUtils.isEmpty(linkedHashMaps2.get(0))) {
                    throw new BDException("缺少sheet2真实值");
                }
            }

            algoTemplateFile.setTestFile(fileDto.getPath());
            algoTemplateFile.setTestFileName(fileDto.getFileName());
        }
        if (algoTemplateFile.insert()) {
            return Response.success(algoTemplateFile);
        } else throw new BDException("保存失败");
    }

    @PostMapping("/updateAll")
    @ApiOperation(httpMethod = "POST", value = "修改所有")
    public Response<String> updateAll(AlgoTemplateFile algoTemplateFile, @RequestParam(value = "file", required = false) MultipartFile file) {
        if (file != null) {
            FileDto fileDto = fileService.uploadFile(file, new FileDto("testAlgo"));


            AbstractNoModelDataListener abstractNoModelDataListener = new AbstractNoModelDataListener(commonAnalyzeService, new HashMap<>());
            EasyExcel.read(fileDto.getPath(), abstractNoModelDataListener).sheet().doRead();

            FileContentDto fileContentDto = new FileContentDto();
            fileContentDto.setContent(abstractNoModelDataListener.resultDataList);
            fileContentDto.setTitle(abstractNoModelDataListener.titleList);

            List<List<String>> linkedHashMaps = fileContentDto.getListList();
            if (CollectionUtils.isEmpty(linkedHashMaps)) {
                throw new BDException("缺少内容");
            }

            if (algoTemplateFile.getModelCode().equals("1")) {
                AbstractNoModelDataListener abstractNoModelDataListener2 = new AbstractNoModelDataListener(commonAnalyzeService, new HashMap<>());
                EasyExcel.read(fileDto.getPath(), abstractNoModelDataListener2).sheet(1).doRead();

                FileContentDto fileContentDto2 = new FileContentDto();
                fileContentDto2.setContent(abstractNoModelDataListener2.resultDataList);
                fileContentDto2.setTitle(abstractNoModelDataListener2.titleList);

                List<List<String>> linkedHashMaps2 = fileContentDto2.getListList();
                if (CollectionUtils.isEmpty(linkedHashMaps2) || CollectionUtils.isEmpty(linkedHashMaps2.get(0))) {
                    throw new BDException("缺少sheet2真实值");
                }
            }

            algoTemplateFile.setTestFileName(fileDto.getFileName());
            algoTemplateFile.setTestFile(fileDto.getPath());
        }
        if (!algoTemplateFile.updateById()) {
            throw new BDException("修改失败");
        }
        return Response.success("修改成功");
    }

    @PostMapping("/uploadTemp")
    @ApiOperation(httpMethod = "POST", value = "保存")
    public Response<AlgoTemplateFile> uploadTemp(Long id, @RequestParam(value = "file", required = false) MultipartFile file) {
        AlgoTemplateFile algoTemplateFile = u.getById(id);
        if (file != null) {
            FileDto fileDto = fileService.uploadFile(file, new FileDto("testTempAlgo"));
            algoTemplateFile.setTempFile(fileDto.getPath());
        }
        if (algoTemplateFile.updateById()) {
            return Response.success(algoTemplateFile);
        } else throw new BDException("保存失败");
    }

    @PostMapping("/downloadTestList")
    @ApiOperation(httpMethod = "POST", value = "下载测试文件")
    public void downloadTestList(Long id, Integer temp, HttpServletResponse response) throws UnsupportedEncodingException {
        AlgoTemplateFile algoTemplateFile = u.getById(id);
        String path = (temp != null && temp == 1) ? algoTemplateFile.getTempFile() : algoTemplateFile.getTestFile();
        fileService.downloadFile(response, path, algoTemplateFile.getAlgoName() + path.substring(path.lastIndexOf(".")));
    }


    @GetMapping("/testList")
    @ApiOperation(httpMethod = "GET", value = "获取测试文件列表")
    public Response<PageDto<LinkedHashMap<String, String>>> testList(Long id, Integer temp, PageParams pageParams) {
        AlgoTemplateFile algoTemplateFile = u.getById(id);
        FileContentDto fileContentDto = new FileContentDto();
        AbstractNoModelDataListener abstractNoModelDataListener = new AbstractNoModelDataListener(commonAnalyzeService, new HashMap<>());
        EasyExcel.read((temp != null && temp == 1) ? algoTemplateFile.getTempFile() : algoTemplateFile.getTestFile(), abstractNoModelDataListener).sheet().doRead();
        fileContentDto.setContent(abstractNoModelDataListener.resultDataList);
        fileContentDto.setTitle(abstractNoModelDataListener.titleList);

        List<LinkedHashMap<String, String>> list = fileContentDto.getListMap();
        PageDto<LinkedHashMap<String, String>> pageDto = new PageDto<>();
        pageDto.setPage(pageParams.getPage());
        pageDto.setPageSize(pageParams.getPageSize());
        pageDto.setRowCount(list.size());
        int start = Integer.parseInt(String.valueOf((pageParams.getPage() - 1) * pageParams.getPageSize()));
        int end = Integer.parseInt(String.valueOf((pageParams.getPage() - 1) * pageParams.getPageSize() + pageParams.getPageSize()));
        pageDto.setList(list.subList(start, Math.min(end, list.size())));
        return Response.success(pageDto);
    }

    @GetMapping("/lastTestList")
    @ApiOperation(httpMethod = "GET", value = "获取测试文件最后数据")
    public Response<List<String>> lastTestList(Long id, Integer temp) {
        AlgoTemplateFile algoTemplateFile = u.getById(id);
        FileContentDto fileContentDto = new FileContentDto();
        AbstractNoModelDataListener abstractNoModelDataListener = new AbstractNoModelDataListener(commonAnalyzeService, new HashMap<>());
        EasyExcel.read((temp != null && temp == 1) ? algoTemplateFile.getTempFile() : algoTemplateFile.getTestFile(), abstractNoModelDataListener).sheet().doRead();
        fileContentDto.setContent(abstractNoModelDataListener.resultDataList);
        fileContentDto.setTitle(abstractNoModelDataListener.titleList);

        List<List<String>> list = fileContentDto.getListList();
        List<String> result = new ArrayList<>();
        list.forEach(result::addAll);

        int start = Math.min(100, result.size());

        return Response.success(result.subList(result.size() - start, result.size()));
    }

    /**
     * 高校算法测试
     */
    @PostMapping("/testAlgo")
    @ApiOperation(httpMethod = "POST", value = "高校算法测试算法")
    public Response<Object> testAlgo(String id, Integer temp, Long page, Long pageSize, HttpServletRequest request) throws Exception {
        if (page == null || page == 0) {
            page = 1L;
        }
        if (pageSize == null || pageSize == 0) {
            pageSize = 10L;
        }
        // 1、根据负载均衡器获取选择一台训练服务器
        TrainingServerDto serverDto = serverBalancer.chooseMachine();
        serverDto.setWaitTime(0);
        // 向此训练服务器发送停止任务,调用算法训练端ip/testAlgo接口

        String url = "http://" + serverDto.getIp() + "/testAlgo";
        HttpHeaders headers = initRestTemplateHeader();

        String username = request.getParameter(LoginConstants.REQUEST_PARAM_USERNAME);
        AlgoTemplateFile algoTemplateFile = u.getById(id);
        AbstractNoModelDataListener abstractNoModelDataListener = new AbstractNoModelDataListener(commonAnalyzeService, new HashMap<>());
        EasyExcel.read((temp != null && temp == 1) ? algoTemplateFile.getTempFile() : algoTemplateFile.getTestFile(), abstractNoModelDataListener).sheet().doRead();
        FileContentDto fileContentDto = new FileContentDto(abstractNoModelDataListener);

        //JAVA算法
        Object o1 = exec(algoTemplateFile.getAlgoCode(),fileContentDto);
        if(o1!=null){
            return Response.success(JSONUtil.toJsonStr(o1));
        }

        List<String[]> list = abstractNoModelDataListener.getListStr();
        // 请求体
        Map<String, Object> postParameters = new HashMap<>();
        postParameters.put("dataArr", list);
        postParameters.put("testFileUrl", algoTemplateFile.getTestFile());
        postParameters.put("algoName", algoTemplateFile.getAlgoCode());
        String jsonBody = JSON.toJSONString(postParameters);
        HttpEntity<String> r = new HttpEntity<>(jsonBody, headers);
        ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, r, String.class);

        // 返回结果
        String body = postForEntity.getBody();
        JSONObject jsObj = JSONObject.parseObject(body);
        if (jsObj.getInteger("ret") != null && 0 == jsObj.getInteger("ret")) {
            System.err.println("--------true-----------");
            System.err.println(jsObj);
            JSONArray array = JSONArray.parseArray(jsObj.getString("result"));
            List<String> r2 = new ArrayList<>();
            for (Object o : array) {
                JSONArray data = JSONArray.parseArray(o.toString());
                r2.add(data.get(0).toString());
            }

            if (algoTemplateFile.getModelCode().equals("1")) {

                AbstractNoModelDataListener abstractNoModelDataListener2 = new AbstractNoModelDataListener(commonAnalyzeService, new HashMap<>());
                EasyExcel.read((temp != null && temp == 1) ? algoTemplateFile.getTempFile() : algoTemplateFile.getTestFile(), abstractNoModelDataListener2).sheet(1).doRead();
                FileContentDto fileContentDto2 = new FileContentDto(abstractNoModelDataListener2);
                List<Map<String, Object>> result = new ArrayList<>();
                int passCount = 0;
                List<List<String>> list2 = fileContentDto2.getListList();
                for (int i = 0; i < list2.size(); i++) {
                    Map<String, Object> resultMap = new HashMap<>();
                    String real = list2.get(i).get(0);
                    String predict = String.valueOf(r2.get(i));
                    String pass = real.equals(predict) ? "通过" : "不通过";
                    if (real.equals(predict)) passCount++;
                    resultMap.put("real", real);
                    resultMap.put("predict", predict);
                    resultMap.put("pass", pass);
                    result.add(resultMap);
                }
                BigDecimal rate = new BigDecimal(passCount).divide(new BigDecimal(list2.size()), 2, RoundingMode.UP);
                PageDto<Map<String, Object>> pageDto = new PageDto<>();
                pageDto.setPage(page);
                pageDto.setPageSize(pageSize);
                pageDto.setRowCount(result.size());
                int start = Integer.parseInt(String.valueOf((page - 1) * pageSize));
                int end = Integer.parseInt(String.valueOf((page - 1) * pageSize + pageSize));
                pageDto.setList(result.subList(start, Math.min(end, result.size())));
                JSONObject o = new JSONObject();
                o.put("page", pageDto);
                o.put("rate", rate.doubleValue());
                return Response.success(o);
            } else {
                return Response.success(r2);
            }

        } else {
            System.err.println("--------false-----------");
            Integer ret = jsObj.getInteger("ret") != null ? jsObj.getInteger("ret") : 0;
            String msg = StringUtils.isNotBlank(jsObj.getString("msg")) ? jsObj.getString("msg") : "";
            throw new BDException(msg);
        }
    }

    private Object exec(String methodName, FileContentDto fileContentDto) throws InvocationTargetException, IllegalAccessException {
        Method method1 = null;
        for (Method method:DataAnalysisUtil.class.getMethods()) {
            if (method.getName().equals(methodName)) {
                method1=method;
            }
        }
        if(method1==null){
            return null;
        }
        switch (methodName){
            case "dauWaveTrans"://1.小波变换算法,-----------单个double数组---------
            case "duaNormalize"://5.Z-Score标准化算法
            case "dauBysigma"://7.基于标准差值的状态评估算法
            case "dauByPower"://8.基于参数均值的故障诊断算法
            case "duaByTemp"://9.基于参数最大值故障诊断算法
            case "duaByVar"://10.基于方差值的状态评估算法
            case "duaBypp"://11.基于峰峰值的故障诊断算法
            case "duaByave"://12.基于均值的状态评估算法
            case "duaByMax"://13.基于最大值的状态评估算法
            case "duaByMin"://14.基于最小值的状态评估算法
            case "duaNorMaxValue"://15.最大归一化算法
            case "duaNorMinMax"://16.最大最小值归一化算法
            case "duaCentralization"://19.中心化标准化算法
                Object d = DataObjectConvertUtil.convert(Arrays.asList(fileContentDto.getVerticalList().get(0)), DataTypeEnum.FLOAT2.getCode());
                return method1.invoke(new DataAnalysisUtil(),d);
            case "dauCorrelation"://2.相关性分析------------两个double数组----------
            case "dauFisherAnalysis"://3.Fisher判别分析算法
            case "duaRankSum"://6.秩和检验算法
            case "duaTTest"://17.TT检验算法
                Object d1 = DataObjectConvertUtil.convert(Arrays.asList(fileContentDto.getVerticalList().get(0)),DataTypeEnum.FLOAT2.getCode());
                Object d2 = DataObjectConvertUtil.convert(Arrays.asList(fileContentDto.getVerticalList().get(1)),DataTypeEnum.FLOAT2.getCode());
                return method1.invoke(new DataAnalysisUtil(),d1,d2);
            case "dauCalMIValue"://4.互信息的聚类相似性度量算法---------------两个map结构-------------
                List<LinkedHashMap<String, String>> listMap = fileContentDto.getListMap();
                Map<String, Integer> param1 = new HashMap<>();
                Map<String, Integer> param2 = new HashMap<>();
                for (Map.Entry<String,String> entry:listMap.get(0).entrySet()){
                    param1.put(entry.getKey(),Integer.valueOf(entry.getValue()));
                }
                for (Map.Entry<String,String> entry:listMap.get(1).entrySet()){
                    param2.put(entry.getKey(),Integer.valueOf(entry.getValue()));
                }
                return DataAnalysisUtil.dauCalMIValue(param1,param2);
            case "duaPCA"://18.PCA主成分分析算法---------------double二维数组------------
                List<List<String>> lists = fileContentDto.getListList();
                double[][] r = new double[lists.size()][];
                for (int i = 0; i < lists.size(); i++) {
                    for (int j = 0; j < lists.get(i).size(); j++) {
                        if(StringUtils.isBlank(lists.get(i).get(j))){
                            r[i][j]= 0;
                        }else{
                            r[i][j]= Double.parseDouble(lists.get(i).get(j));
                        }
                    }
                }
//                return DataAnalysisUtil.dauCalMIValue(param1,param2);
            default:return null;
        }
    }
    private static HttpHeaders initRestTemplateHeader() {

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);// 请求类型
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());// 接收类型
        return headers;
    }


}

